#include "GLSceneMapDrawers.h"

#include <vector>
#include <cmath>

#include "PathCoordinate.h"

namespace catan
{

/*private*/ GLSceneMapDrawers::GLSceneMapDrawers()
{
}

/*static*/ void GLSceneMapDrawers::drawBackground(float multiplier, GLuint backgroundTexture)
{
	GLfloat oldColor[4];
	glGetFloatv(GL_CURRENT_COLOR, oldColor);
	GLint oldTexture;
	glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexture);
	    glColor3f(0.5f, 0.5f, 0.5f);
	    glBindTexture(GL_TEXTURE_2D, backgroundTexture);
	    glBegin(GL_QUADS);
	    	glTexCoord2f(1.0f, 0.0f);
		    glVertex3f(0.5f*multiplier, -0.5f*multiplier, 0.0f);
		    
	    	glTexCoord2f(0.0f, 0.0f);
		    glVertex3f(-0.5f*multiplier, -0.5f*multiplier, 0.0f);
		    
	    	glTexCoord2f(0.0f, 1.0f);
		    glVertex3f(-0.5f*multiplier, 0.5f*multiplier, 0.0f);
		    
	    	glTexCoord2f(1.0f, 1.0f);
		    glVertex3f(0.5f*multiplier, 0.5f*multiplier, 0.0f);
	    glEnd();
    glBindTexture(GL_TEXTURE_2D, oldTexture);
	glColor3f(oldColor[0], oldColor[1], oldColor[2]);
}

/*static*/ void GLSceneMapDrawers::drawHexagons(float multiplier, GLTextures &glTextures, GameMap &gameMap, std::vector<SiteCoordinate> &settlements, std::map<SiteCoordinate, int> &settlementColors, std::vector<PathCoordinate> &roads, std::map<PathCoordinate, int> &roadColors)
{
    for (int j=0; j<7; ++j)
    {
    	for (int i=0; i<7; ++i)
    	{
    		int iPlusJ = i+j;
    		if (iPlusJ < 3 || iPlusJ > 9) continue;
	    	GLuint texture;
	    	CoordinateX coordinateX(static_cast<CoordinateX::Enum_CoordinateX>(i));
	    	CoordinateY coordinateY(static_cast<CoordinateY::Enum_CoordinateY>(j));
	    	Cell cell = gameMap.getCell(CellCoordinate(coordinateX, coordinateY));
			CellType cellType = cell.getType();
			if (cellType == pastureType) texture = glTextures.getSheepTexture();
			else if (cellType == forestType) texture = glTextures.getWoodsTexture();
			else if (cellType == fieldsType) texture = glTextures.getWheatTexture();
			else if (cellType == hillsType) texture = glTextures.getBrickTexture();
			else if (cellType == mountainsType) texture = glTextures.getOreTexture();
			else if (cellType == desertType) texture = glTextures.getDesertTexture();
			else if (cellType == generalHarborType) texture = glTextures.getGeneralHarborTexture();
			else if (cellType == woodHarborType) texture = glTextures.getWoodHarborTexture();
			else if (cellType == sheepHarborType) texture = glTextures.getSheepHarborTexture();
			else if (cellType == wheatHarborType) texture = glTextures.getWheatHarborTexture();
			else if (cellType == brickHarborType) texture = glTextures.getBrickHarborTexture();
			else if (cellType == oreHarborType) texture = glTextures.getOreHarborTexture();
			else texture = glTextures.getSeaTexture();
			CellNumber cellNumber = cell.getNumber();
    		GLSceneMapDrawers::drawHexagon(texture, glTextures.getTileTexture(cellNumber.getEnum()), i, j, multiplier*0.16, settlements, settlementColors, roads, roadColors);
    	}
    }	
}

/*static*/ void GLSceneMapDrawers::drawHexagon(GLuint texture, GLuint numberTexture, int x, int y, float multiplier, std::vector<SiteCoordinate> &settlements, std::map<SiteCoordinate, int> &settlementColors, std::vector<PathCoordinate> &roads, std::map<PathCoordinate, int> &roadColors)
{
	static const float hexagonX[6] = {0.5f, 0.25f, -0.25f, -0.5f, -0.25f, 0.25f};
	static const float hexagonY[6] = {0.0f, -0.4330127018922f, -0.4330127018922f, 0.0f, 0.4330127018922f, 0.4330127018922f};
	float xShift = 0.75f*(x-3);
	float yShift = (0.4330127018922193f*(x-3) + 0.8660254037844386f*(y-3));
	if (texture != 0)
	{
		glBindTexture(GL_TEXTURE_2D, texture);
	}
    glBegin(GL_POLYGON);
    	for (int k=0; k<6; ++k)
    	{
			glTexCoord2f(hexagonX[k]+0.5f, hexagonY[k]+0.5f);
	        glVertex3f((hexagonX[k]*0.9f+xShift)*multiplier, (hexagonY[k]*0.9f+yShift)*multiplier, (0.04f)*multiplier);
    	}
    glEnd();
    if (texture != 0)
    {
    	glBindTexture(GL_TEXTURE_2D, 0);
    }
    glBegin(GL_QUADS);
	    for (int k=0; k<6; ++k)
	    {
	        glColor3f(0.92549019607843142f*((abs(3-k)+2)*0.2f), 0.81568627450980391f*((abs(3-k)+2)*0.2f), 0.51764705882352946f*((abs(3-k)+2)*0.2f));
		    glVertex3f((hexagonX[k]*0.9f+xShift)*multiplier, (hexagonY[k]*0.9f+yShift)*multiplier, (0.04f)*multiplier);
		    glVertex3f((hexagonX[(k+1)%6]*0.9f+xShift)*multiplier, (hexagonY[(k+1)%6]*0.9f+yShift)*multiplier, (0.04f)*multiplier);
		    glVertex3f((hexagonX[(k+1)%6]*1.0f+xShift)*multiplier, (hexagonY[(k+1)%6]*0.95f+yShift)*multiplier, 0.0f);
		    glVertex3f((hexagonX[k]*1.0f+xShift)*multiplier, (hexagonY[k]*0.95f+yShift)*multiplier, 0.0f);
	    }
    glEnd();
	for (std::vector<PathCoordinate>::const_iterator roadIterator = roads.begin(); roadIterator != roads.end(); ++roadIterator)
	{
		if (roadIterator->getCoordinateX().getEnum() == x && roadIterator->getCoordinateY().getEnum() == y)
		{
			int color = roadColors.find(*roadIterator)->second;
			float r;
			float g;
			float b;
			switch (color)
			{
			case 0:
				r = 1.0f;
				g = 0.0f;
				b = 0.0f;
				break;
			case 1:
				r = 0.0f;
				g = 1.0f;
				b = 0.0f;
				break;
			case 2:
				r = 0.0f;
				g = 0.0f;
				b = 1.0f;
				break;
			case 3:
				r = 1.0f;
				g = 1.0f;
				b = 0.0f;
				break;
			}
	        glColor3f(r, g, b);
	        glBegin(GL_QUADS);
			int k;
			switch ((int)roadIterator->getVerticalCardinal().getEnum())
			{
			case 30:
				k=0;
				
				break;
			case 150:
				k=2;
				break;
			case 270:
				k=4;
				break;
			}
		    glVertex3f((hexagonX[k]*0.9f+xShift)*multiplier, (hexagonY[k]*0.9f+yShift)*multiplier, (0.1f)*multiplier);
		    glVertex3f((hexagonX[(k+1)%6]*0.9f+xShift)*multiplier, (hexagonY[(k+1)%6]*0.9f+yShift)*multiplier, (0.1f)*multiplier);
		    glVertex3f((hexagonX[(k+1)%6]*1.1f+xShift)*multiplier, (hexagonY[(k+1)%6]*1.1f+yShift)*multiplier, 0.1f*multiplier);
		    glVertex3f((hexagonX[k]*1.1f+xShift)*multiplier, (hexagonY[k]*1.1f+yShift)*multiplier, 0.1f*multiplier);
		    glEnd();

	        glColor3f(1.0f, 1.0f, 1.0f);
	        
		}
	}
	for (std::vector<SiteCoordinate>::const_iterator settlementIterator = settlements.begin(); settlementIterator != settlements.end(); ++settlementIterator)
	{
		if (settlementIterator->getCoordinateX().getEnum() == x && settlementIterator->getCoordinateY().getEnum() == y)
		{
			int color = settlementColors.find(*settlementIterator)->second;
			float r;
			float g;
			float b;
			switch (color)
			{
			case 0:
				r = 1.0f;
				g = 0.0f;
				b = 0.0f;
				break;
			case 1:
				r = 0.0f;
				g = 1.0f;
				b = 0.0f;
				break;
			case 2:
				r = 0.0f;
				g = 0.0f;
				b = 1.0f;
				break;
			case 3:
				r = 1.0f;
				g = 1.0f;
				b = 0.0f;
				break;
			}
	        glColor3f(r, g, b);
	        glBegin(GL_QUADS);
			int l;
			switch ((int)settlementIterator->getHorizontalCardinal().getEnum())
			{
			case 0:
				l=0;
				break;
			case 180:
				l=3;
				break;
			}
			float xOffset = (hexagonX[l]);
			float yOffset = (hexagonY[l]);
		    glBegin(GL_POLYGON);
		    	for (int k=0; k<6; ++k)
		    	{
			        glVertex3f((hexagonX[k]*0.9f+xShift+xOffset)*multiplier, (hexagonY[k]*0.9f+yShift+yOffset)*multiplier, (0.11f)*multiplier);
		    	}
		    glEnd();

	        glColor3f(1.0f, 1.0f, 1.0f);
	        
		}
	}
	if (numberTexture != 0)
	{
        glColor3f(1.0f, 1.0f, 1.0f);
		glBindTexture(GL_TEXTURE_2D, numberTexture);
	    glBegin(GL_POLYGON);
	    	int circleSteps = 12;
	    	for (int k=0; k<circleSteps; ++k)
	    	{
	    		float theta = (float)k/circleSteps*2*M_PI;
	    		float xPart = cos(theta)/2;
	    		float yPart = sin(theta)/2;
				glTexCoord2f(xPart+0.5f, yPart+0.5f);
		        glVertex3f((xPart*0.3f+xShift)*multiplier, (yPart*0.3f+yShift)*multiplier, (0.05f)*multiplier);
	    	}
	    glEnd();
		glBindTexture(GL_TEXTURE_2D, 0);
	}
	glColor3f(1.0f, 1.0f, 1.0f);
}

}
